home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / fontutil.6 / fontutil / fontutils-0.6 / bzr / bzr_input.c next >
Encoding:
C/C++ Source or Header  |  1992-10-18  |  10.9 KB  |  418 lines

  1. /* bzr_input.c: read a BZR-format font file.
  2.  
  3. Copyright (C) 1992 Free Software Foundation, Inc.
  4.  
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include "bzr.h"
  22. #include "file-input.h"
  23. #include "scaled-num.h"
  24. #include "spline.h"
  25.  
  26. #include "bzr_opcodes.h"
  27. #include "bzr_types.h"
  28.  
  29. /* Where the input will come from.  */
  30. static FILE *bzr_input_file = NULL;
  31. static string bzr_input_filename;
  32.  
  33.  
  34. /* We remember the design size, so we can scale by it.  */
  35. static real design_size;
  36.  
  37.  
  38. /* The character locators are part of the postamble.  */
  39. static char_locator_type char_loc[MAX_CHARCODE + 1];
  40.  
  41.  
  42. /* Low-level input.  These macros call the corresponding lib routines
  43.    with the static variables for the input file and filename.  */
  44.  
  45. #define BZR_GET_BYTE() get_byte (bzr_input_file, bzr_input_filename)
  46. #define BZR_GET_PREVIOUS_BYTE() \
  47.   get_previous_byte (bzr_input_file, bzr_input_filename)
  48. #define BZR_GET_TWO() get_two (bzr_input_file, bzr_input_filename)
  49. #define BZR_GET_FOUR() get_four (bzr_input_file, bzr_input_filename)
  50. #define BZR_GET_PREVIOUS_FOUR() \
  51.   get_previous_four (bzr_input_file, bzr_input_filename);
  52. #define BZR_FSEEK(offset, from_where) \
  53.   xfseek (bzr_input_file, (long) offset, from_where, bzr_input_filename)
  54.  
  55. /* These routines read a somewhat higher-level value.  */
  56. static real bzr_get_abbrev_scaled (void);
  57. static real bzr_get_scaled (void);
  58. static real bzr_get_abbrev_design_scaled (void);
  59. static real bzr_get_design_scaled (void);
  60. static real_coordinate_type bzr_get_abbrev_point (void);
  61. static real_coordinate_type bzr_get_point (void);
  62.  
  63. /* Open the input file as name FILENAME.  We allow only one input file
  64.    at a time.  */
  65.  
  66. extern boolean
  67. bzr_open_input_file (string filename)
  68. {
  69.   if (bzr_input_file != NULL)
  70.     FATAL2 ("bzr_open_input_file: Attempt to open `%s', but `%s' is
  71. already open", filename, bzr_input_filename);
  72.  
  73.   bzr_input_filename = filename;
  74.   bzr_input_file = fopen (filename, "r");
  75.   
  76.   if (bzr_input_file != NULL)
  77.     {
  78.       unsigned this_char;
  79.  
  80.       for (this_char = 0; this_char <= MAX_CHARCODE; this_char++)
  81.         CHAR_POINTER (char_loc[this_char]) = NULL_BYTE_PTR;
  82.       return true;
  83.     }
  84.   else
  85.     return false;
  86. }
  87.  
  88.  
  89. /* Close the input file and clear all the state variables.  It's an
  90.    error to close the file before it's been opened.  */
  91.  
  92. void
  93. bzr_close_input_file ()
  94. {
  95.   assert (bzr_input_file != NULL);
  96.   
  97.   xfclose (bzr_input_file, bzr_input_filename);
  98.   bzr_input_file = NULL;
  99.   bzr_input_filename = NULL;
  100. }
  101.  
  102. /* The preamble.  Since many numbers in the BZR file are scaled by the
  103.    design size, we squirrel that value away.  */
  104.  
  105. bzr_preamble_type
  106. bzr_get_preamble ()
  107. {
  108.   one_byte comment_length;
  109.   bzr_preamble_type p;
  110.   
  111.   assert (bzr_input_file != NULL);
  112.  
  113.   BZR_FSEEK (0, SEEK_SET);
  114.   design_size = BZR_DESIGN_SIZE (p) = bzr_get_scaled ();
  115.   if (design_size <= 0.0)
  116.     {
  117.       WARNING1 ("bzr_get_preamble: Strange design size %f changed to 128pt",
  118.                 design_size);
  119.       design_size = 128.0;
  120.     }
  121.  
  122.   comment_length = BZR_GET_BYTE ();
  123.   if (comment_length == 0)
  124.     BZR_COMMENT (p) = "";
  125.   else
  126.     {
  127.       BZR_COMMENT (p) = get_n_bytes (comment_length, bzr_input_file,
  128.                                      bzr_input_filename);
  129.       BZR_COMMENT (p) = xrealloc (BZR_COMMENT (p), comment_length + 1);
  130.       BZR_COMMENT (p)[comment_length] = 0;
  131.     }
  132.  
  133.   return p;
  134. }
  135.  
  136. /* Read the character with code CODE and return it, or NULL if the
  137.    character doesn't exist.  Also skip leading no-ops.  */
  138.  
  139. bzr_char_type *
  140. bzr_get_char (charcode_type code)
  141. {
  142.   byte_count_type char_ptr;
  143.   
  144.   assert (bzr_input_file != NULL);
  145.   
  146.   /* First find the position of the character by reading the character
  147.      locators (if we haven't already done so).  */
  148.   if (char_loc == NULL)
  149.     (void) bzr_get_postamble ();
  150.   
  151.   /* If the character isn't in the file, return NULL.  */
  152.   char_ptr = CHAR_POINTER (char_loc[code]);
  153.   if (char_ptr == NULL_BYTE_PTR)
  154.     return NULL;
  155.     
  156.   /* Move to the beginning of the character definition.  */
  157.   BZR_FSEEK (char_ptr, SEEK_SET);
  158.   
  159.   return bzr_get_next_char ();
  160. }
  161.  
  162.  
  163. /* This returns the character starting at the current position in
  164.    `bzr_input_file', or NULL if we are at the postamble, or gives a
  165.    fatal error if we're not at either.  */
  166.  
  167. bzr_char_type *
  168. bzr_get_next_char ()
  169. {
  170.   bzr_char_type *c;
  171.   one_byte command;
  172.   real_coordinate_type current_point;
  173.   real (*get_num) (void);
  174.   real_coordinate_type (*get_point) (void);
  175.   spline_list_type list;
  176.   boolean no_current_point = true;
  177.  
  178.   assert (bzr_input_file);
  179.  
  180.   command = BZR_GET_BYTE ();
  181.   if (command == BOC)
  182.     get_num = bzr_get_design_scaled;
  183.   else if (command == BOC_ABBREV)
  184.     get_num = bzr_get_abbrev_design_scaled;
  185.   else if (command == POST)
  186.     return NULL;
  187.   else
  188.     FATAL1 ("bzr_get_next_char: Expected BOC or POST, found %u", command);
  189.   
  190.   c = XTALLOC1 (bzr_char_type);
  191.   
  192.   /* Read the beginning-of-character information that is always present.  */
  193.   CHARCODE (*c) = BZR_GET_BYTE ();
  194.   CHAR_SET_WIDTH (*c) = get_num ();
  195.   CHAR_MIN_COL (*c) = get_num ();
  196.   CHAR_MIN_ROW (*c) = get_num ();
  197.   CHAR_MAX_COL (*c) = get_num ();
  198.   CHAR_MAX_ROW (*c) = get_num ();
  199.   
  200.   if (CHAR_MIN_COL (*c) > CHAR_MAX_COL (*c))
  201.     {
  202.       WARNING2 ("bzr_get_next_char: Min col %f > max col %f",
  203.                CHAR_MIN_COL (*c), CHAR_MAX_COL (*c));
  204.       CHAR_MIN_COL (*c) = CHAR_MAX_COL (*c);
  205.     }
  206.   if (CHAR_MIN_ROW (*c) > CHAR_MAX_ROW (*c))
  207.     {
  208.       WARNING2 ("bzr_get_next_char: Min row %f > max row %f",
  209.                CHAR_MIN_ROW (*c), CHAR_MAX_ROW (*c));
  210.       CHAR_MIN_ROW (*c) = CHAR_MAX_ROW (*c);
  211.     }
  212.   
  213.   /* Read the shape.  */
  214.   BZR_SHAPE (*c) = new_spline_list_array ();
  215.   list = *new_spline_list ();
  216.   
  217.   while ((command = BZR_GET_BYTE ()) != EOC)
  218.     {
  219.       switch (command)
  220.         {
  221.         case START_PATH:
  222.           no_current_point = false;
  223.           current_point = bzr_get_point ();
  224.           
  225.           /* At the first START_PATH we come to, `list' will be empty.
  226.              If by chance the shape does have two consecutive
  227.              START_PATH's, there's no point in remembering the first,
  228.              anyway.  */
  229.           if (SPLINE_LIST_LENGTH (list) > 0)
  230.             {
  231.               append_spline_list (&BZR_SHAPE (*c), list);
  232.               list = *new_spline_list ();
  233.             }
  234.           break;
  235.       
  236.         case SPLINE:
  237.         case SPLINE_ABBREV:
  238.           {
  239.             spline_type s = new_spline ();
  240.             SPLINE_DEGREE (s) = CUBIC;
  241.  
  242.             if (no_current_point)
  243.               {
  244.                 WARNING ("bzr_get_next_char: Spline before path started");
  245.                 current_point = (real_coordinate_type) { 0.0, 0.0 };
  246.               }
  247.  
  248.             get_point
  249.               = command == SPLINE ? bzr_get_point : bzr_get_abbrev_point;
  250.  
  251.             START_POINT (s) = current_point;
  252.             CONTROL1 (s) = get_point ();
  253.             CONTROL2 (s) = get_point ();
  254.             current_point = END_POINT (s) = get_point ();
  255.  
  256.             append_spline (&list, s);
  257.             break;
  258.           }
  259.       
  260.         case LINE:
  261.         case LINE_ABBREV:
  262.           {
  263.             spline_type s = new_spline ();
  264.             SPLINE_DEGREE (s) = LINEAR;
  265.  
  266.             if (no_current_point)
  267.               {
  268.                 WARNING ("bzr_get_next_char: Line before path started");
  269.                 current_point = (real_coordinate_type) { 0.0, 0.0 };
  270.               }
  271.  
  272.             get_point = command == LINE ? bzr_get_point : bzr_get_abbrev_point;
  273.  
  274.             START_POINT (s) = current_point;
  275.             current_point = END_POINT (s) = get_point ();
  276.  
  277.             append_spline (&list, s);
  278.             break;
  279.           }
  280.       
  281.         case NO_OP:
  282.           break;
  283.       
  284.         default:
  285.           FATAL1 ("bzr_get_char: Expected path command, found %u", command);
  286.         }
  287.     }
  288.  
  289.   append_spline_list (&BZR_SHAPE (*c), list);
  290.   
  291.   return c;
  292. }
  293.  
  294. /* We find the POST byte by starting at the end of the file and reading
  295.    backwards until we get to the pointer.  Then we follow the pointer
  296.    and read the postamble forwards.  */
  297.  
  298. bzr_postamble_type
  299. bzr_get_postamble ()
  300. {
  301.   one_byte command;
  302.   byte_count_type post_ptr;
  303.   bzr_postamble_type p;
  304.  
  305.   assert (bzr_input_file != NULL);
  306.   
  307.   BZR_FSEEK (0, SEEK_END);
  308.   
  309.   /* We should find at least one NO_OP at the end.  */
  310.   do
  311.     command = BZR_GET_PREVIOUS_BYTE ();
  312.   while (command == NO_OP);
  313.   
  314.   if (command != BZR_ID)
  315.     WARNING1 ("bzr_get_postamble: Expected BZR id, found %u", command);
  316.   
  317.   post_ptr = BZR_GET_PREVIOUS_FOUR ();
  318.   BZR_FSEEK (post_ptr, SEEK_SET);
  319.   
  320.   command = BZR_GET_BYTE ();
  321.   if (command != POST)
  322.     FATAL1 ("bzr_get_postamble: Expected POST, found %u", command);
  323.  
  324.   MIN_COL (BZR_FONT_BB (p)) = bzr_get_design_scaled ();
  325.   MIN_ROW (BZR_FONT_BB (p)) = bzr_get_design_scaled ();
  326.   MAX_COL (BZR_FONT_BB (p)) = bzr_get_design_scaled ();
  327.   MAX_ROW (BZR_FONT_BB (p)) = bzr_get_design_scaled ();
  328.   
  329.   /* The character locators.  */
  330.   while ((command = BZR_GET_BYTE ()) == CHAR_LOC || command == CHAR_LOC_ABBREV)
  331.     {
  332.       one_byte code = BZR_GET_BYTE ();
  333.       if (CHAR_POINTER (char_loc[code]) != NULL_BYTE_PTR)
  334.         WARNING1 ("bzr_get_postamble: Second locator for character %u",
  335.                   code);
  336.       CHAR_POINTER (char_loc[code])
  337.         = command == CHAR_LOC ? BZR_GET_FOUR () : BZR_GET_TWO ();
  338.     }
  339.  
  340.   BZR_NCHARS (p) = command;
  341.  
  342.   return p;
  343. }
  344.  
  345. /* Low-level input routines.  */
  346.  
  347. /* Because the scaled numbers in the file are only three bytes long, we
  348.    have to read the most significant byte into an integer, so that the
  349.    sign extension will be done by the compiler.  */
  350.  
  351. static real
  352. bzr_get_scaled ()
  353. {
  354.   signed_byte x;
  355.   scaled s;
  356.  
  357.   x = BZR_GET_BYTE ();
  358.   s = x << 16;;
  359.   s |= BZR_GET_BYTE () << 8;
  360.   s |= BZR_GET_BYTE ();
  361.   
  362.   return scaled_to_real (s);
  363. }
  364.  
  365.  
  366. static real
  367. bzr_get_design_scaled ()
  368. {
  369.   return bzr_get_scaled () * design_size;
  370. }
  371.  
  372.  
  373. static real_coordinate_type
  374. bzr_get_point ()
  375. {
  376.   real_coordinate_type c;
  377.   
  378.   c.x = bzr_get_design_scaled ();
  379.   c.y = bzr_get_design_scaled ();
  380.   
  381.   return c;
  382. }
  383.  
  384.  
  385. /* Most numbers in a BZR file are less than the design size.  */
  386.  
  387. static real
  388. bzr_get_abbrev_scaled ()
  389. {
  390.   signed_byte x;
  391.   scaled s;
  392.  
  393.   x = BZR_GET_BYTE ();
  394.   s = x << 8;
  395.   s |= BZR_GET_BYTE ();
  396.   
  397.   return scaled_to_real (s);
  398. }
  399.  
  400.  
  401. static real
  402. bzr_get_abbrev_design_scaled ()
  403. {
  404.   return bzr_get_abbrev_scaled () * design_size;
  405. }
  406.  
  407.  
  408. static real_coordinate_type
  409. bzr_get_abbrev_point ()
  410. {
  411.   real_coordinate_type c;
  412.   
  413.   c.x = bzr_get_abbrev_design_scaled ();
  414.   c.y = bzr_get_abbrev_design_scaled ();
  415.   
  416.   return c;
  417. }
  418.